﻿using System;
using UBlockly.UI;
using UnityEngine;
using UBlockly.Util;
using System.Collections.Generic;
using UnityEngine.EventSystems;
using System.Text;
using UBlockly.Scriptable;

namespace UBlockly.Sys
{
    public class TranslateSystem : ISystem
    {
        protected override void OnInit(params object[] args)
        {
            base.OnInit(args);
        }

        public string TranslateNodeToScript(Node node)
        {
            var paramstack = NodeStack(node);
            if (paramstack != null && paramstack.Count > 0)
            {
                var p = paramstack.Pop();
                var getter = p.Scriptable.GetFunc().DefaultParamGetter;
                object defaultParam = null;
                if (getter != null)
                    defaultParam = getter();
                string target = p.Scriptable.ToILCallFormat(defaultParam);
                while (paramstack.Count != 0)
                {
                    p = paramstack.Pop();
                    target = p.Scriptable.ToILCallFormat(target);
                }
                return target;
            }
            return "";
        }

        public string TranslateChainToScript(LinkedList<Node> chain)
        {
            LinkedListNode<Node> p = chain.First;
            StringBuilder sb = new StringBuilder();
            while (p != null)
            {
                sb.Append(TranslateNodeToScript(p.Value));
                p = p.Next;
            }
            return sb.ToString();
        }

        public ILFunc TranslateNodeToIL(Node node)
        {
            var paramstack = NodeStack(node);
            if (paramstack != null && paramstack.Count > 0)
            {
                var p = paramstack.Pop();
                ILFunc target = p.Scriptable.GetFunc();
                ILFunc il = target;
                while (paramstack.Count != 0)
                {
                    p = paramstack.Pop();
                    target = p.Scriptable.GetFunc();                   
                    target.InitParam(il);
                    il = target;
                }
                return target;
            }
            return null;
        }

        public void RunNode(Node node)
        {            
            RunNode(TranslateNodeToIL(node));
        }

        public void RunNode(ILFunc func)
        {
            func.TryExcute();
        }

        public void RunChain(LinkedList<Node> chain)
        {
            RunChain(TranslateChainToIL(chain));
        }

        public void RunChain(List<ILFunc> chain)
        {
            if (chain == null || chain.Count == 0)
            {
                Debug.LogError("il chain is null");
                return;
            }
            if (chain.Count == 1)
            {
                RunNode(chain[0]);
                return;
            }
            Queue<VoidILFunc> que = new Queue<VoidILFunc>(chain.Count);
            foreach (var item in chain)
            {
                if (item as VoidILFunc == null)
                {
                    Debug.LogError("严重错误，RunChain 遇到非空类型节点");
                    continue;
                }
                que.Enqueue(item as VoidILFunc);
            }
            RunNode(que.Dequeue(), que);
        }


        public List<ILFunc> TranslateChainToIL(LinkedList<Node> chain)
        {
            List<ILFunc> list = new List<ILFunc>(chain.Count);
            var p = chain.First;
            while (p != null)
            {
                list.Add(TranslateNodeToIL(p.Value));
                p = p.Next;
            }
            return list;
        }

        void RunNode(VoidILFunc node, Queue<VoidILFunc> que)
        {
            if (node == null)
                return;
            node.Excute(() => {
                if (que.Count != 0)
                {
                    RunNode(que.Dequeue(), que);
                }
            });
        }

        Stack<Node> NodeStack(Node root)
        {
            var param = root.NodePacker;
            Stack<Node> stack = new Stack<Node>();
            stack.Push(root);
            while (param != null)
            {
                var pnode = param.GetParam();
                if (pnode != null)
                {
                    stack.Push(pnode);
                    param = pnode.NodePacker;
                }
                else
                {
                    break;
                }
            }
            return stack;
        }

        //Stack<ILFunc> ILFuncStack(ILFunc ilFunc)
        //{
        //    Stack<ILFunc> stack = new Stack<ILFunc>();
        //    stack.Push(ilFunc);
        //    ILFunc ilparam = ilFunc.TryGetParam();
        //    while (ilparam != null)
        //    {
        //        stack.Push(ilparam);
        //        ilparam = ilFunc.TryGetParam();
        //    }
        //    return stack;
        //}
    }

}